# -*- coding: utf-8 -*-
"""
交易业务服务
"""

import logging
from datetime import datetime, date
from typing import List, Dict, Any

# 动态导入数据库管理器（在__init__中处理）
from models.stock_model import StockInfo, ZbfxRecord, MnjtRecord
from services.east_money_service import EastMoneyAPIService
from config.config import TRADE_TIME
from utils.trade_calendar import TradeCalendar


class TradeService:
    """交易业务服务类"""

    def __init__(self):
        # 直接使用Repository
        from repositories.database_factory import database_factory

        self.zbfx_repo = database_factory.get_zbfx_repository()
        self.mnjt_repo = database_factory.get_mnjt_repository()
        self.api_service = EastMoneyAPIService()
        self.logger = logging.getLogger(__name__)
        self.hold_days = TRADE_TIME["hold_days"]
        self.trade_calendar = TradeCalendar()

    def execute_buy_task(self, target_date=None):
        """执行买入任务（9:30执行）"""
        try:
            # 确定执行日期
            execution_date = target_date if target_date else date.today()

            # 检查执行日期是否为交易日
            if not self.trade_calendar.is_trade_day(execution_date):
                self.logger.info(f"日期 {execution_date} 不是交易日，跳过买入任务执行")
                return

            if target_date:
                self.logger.info(f"开始执行买入任务，指定日期: {target_date}")
                # 使用交易日历获取前一个交易日作为推荐数据源
                yesterday = self.trade_calendar.get_previous_trade_day(target_date)
            else:
                self.logger.info("开始执行买入任务")
                # 使用交易日历获取前一个交易日的推荐股票数据
                yesterday = self.trade_calendar.get_previous_trade_day()

            # 使用聚合查询获取昨天的推荐数据
            aggregated_stocks = self.zbfx_repo.get_aggregated_stocks(
                yesterday, aggregation_strategy="sum"
            )

            # 转换聚合结果为统一格式
            new_recommended_stocks = []
            for agg_stock in aggregated_stocks:
                new_recommended_stocks.append(
                    {
                        "StockCode": agg_stock.stock_code,
                        "Reason": agg_stock.aggregated_reason,
                        "Strength": agg_stock.sum_strength,
                        "source": "new_recommendation",
                    }
                )

            # 获取正在监听中的股票
            active_monitoring_stocks = self.mnjt_repo.get_active_monitoring_stocks()
            self.logger.info(
                f"获取到 {len(active_monitoring_stocks)} 只需要持续监听的股票"
            )

            # 合并所有需要买入的股票
            all_stocks_to_buy = new_recommended_stocks.copy()

            for stock in active_monitoring_stocks:
                self.logger.debug(f"添加持续监听股票: {stock['code']}")
                all_stocks_to_buy.append(
                    {
                        "StockCode": stock["code"],
                        "Reason": stock.get(
                            "Reason", "持续监听"
                        ),  # 使用数据库中的原始推荐理由
                        "Strength": 0,  # 持续监听没有强度评分
                        "source": "continuous_monitoring",
                    }
                )

            # 去重处理：同一股票保留更高评分的记录
            unique_stocks = {}
            for stock in all_stocks_to_buy:
                code = stock["StockCode"]
                if code not in unique_stocks:
                    unique_stocks[code] = stock
                else:
                    if stock["Strength"] > unique_stocks[code]["Strength"]:
                        unique_stocks[code] = stock

            selected_stocks = list(unique_stocks.values())

            if not selected_stocks:
                self.logger.warning(f"没有找到需要买入的股票")
                return

            self.logger.info(f"选择了 {len(selected_stocks)} 只股票进行买入")
            self.logger.info(
                f"其中新推荐: {len([s for s in selected_stocks if s.get('source') == 'new_recommendation'])} 只"
            )
            self.logger.info(
                f"持续监听: {len([s for s in selected_stocks if s.get('source') == 'continuous_monitoring'])} 只"
            )

            # 获取股票代码列表
            stock_codes = [stock["StockCode"] for stock in selected_stocks]

            # 批量获取股票价格（开盘价）
            self.logger.info(f"开始获取 {len(stock_codes)} 只股票的价格数据")
            if target_date and target_date != date.today():
                # 如果指定了历史日期，使用历史数据接口，分批处理
                self.logger.info(f"使用历史数据接口获取 {target_date} 的价格")
                stock_prices = {}
                batch_size = 60  # 每批处理60只股票

                for batch_start in range(0, len(stock_codes), batch_size):
                    batch_end = min(batch_start + batch_size, len(stock_codes))
                    batch_codes = stock_codes[batch_start:batch_end]

                    self.logger.info(
                        f"处理价格获取批次: {batch_start//batch_size + 1}/{(len(stock_codes) + batch_size - 1)//batch_size} ({len(batch_codes)} 只股票)"
                    )

                    batch_prices = self.api_service.get_historical_stocks_by_codes(
                        batch_codes, target_date
                    )
                    stock_prices.update(batch_prices)

                    self.logger.info(
                        f"批次完成，已获取 {len(stock_prices)}/{len(stock_codes)} 只股票价格"
                    )
            else:
                # 否则使用实时接口
                self.logger.info("使用实时接口获取当前价格")
                stock_prices = self.api_service.get_stocks_by_codes(stock_codes)

            self.logger.info(f"成功获取到 {len(stock_prices)} 只股票的价格数据")

            success_count = 0
            skip_count = 0

            self.logger.info(f"开始处理 {len(selected_stocks)} 只股票的买入逻辑")

            for i, stock in enumerate(selected_stocks, 1):
                # 每处理10只股票显示一次进度
                if i % 10 == 0 or i == len(selected_stocks):
                    self.logger.info(f"处理进度: {i}/{len(selected_stocks)}")

                stock_code = stock["StockCode"]

                # 检查是否已经买入过（去重）
                check_date = target_date if target_date else date.today()
                if self.mnjt_repo.check_stock_exists_on_date(stock_code, check_date):
                    self.logger.debug(f"股票 {stock_code} 在 {check_date} 已买入，跳过")
                    skip_count += 1
                    continue

                # 获取当前价格
                if stock_code not in stock_prices:
                    self.logger.warning(f"无法获取股票 {stock_code} 的价格信息，跳过")
                    continue

                stock_info = stock_prices[stock_code]
                buy_price = stock_info.open_price or stock_info.current_price

                if not buy_price or buy_price <= 0:
                    self.logger.warning(
                        f"股票 {stock_code} 开盘价异常: {buy_price}，跳过"
                    )
                    continue

                # 构造股票记录 - 确保买入日期是交易日
                buy_date = target_date if target_date else date.today()
                if not self.trade_calendar.is_trade_day(buy_date):
                    self.logger.warning(
                        f"买入日期 {buy_date} 不是交易日，可能存在逻辑问题"
                    )
                stock_data = {
                    "code": stock_code,
                    "reason": stock["Reason"],
                    "score": stock["Strength"],
                    "buy_price": buy_price,
                    "buy_date": buy_date,
                    "close_price": 0,
                    "change_percent": 0,
                    "days": 1,
                    "is_end": "N",
                }

                # 插入记录
                try:
                    self.mnjt_repo.insert_stock_record(stock_data)
                    success_count += 1
                    self.logger.info(
                        f"买入股票 {stock_code}，价格: {buy_price:.2f}，强度: {stock['Strength']}"
                    )
                except Exception as e:
                    self.logger.error(f"插入股票 {stock_code} 记录失败: {e}")

            self.logger.info(
                f"买入任务完成，成功买入: {success_count}，跳过重复: {skip_count}"
            )

        except Exception as e:
            self.logger.error(f"执行买入任务失败: {e}")

    def execute_sell_task(self, target_date=None):
        """执行收盘统计任务（15:00执行）"""
        try:
            # 确定执行日期
            execution_date = target_date if target_date else date.today()

            # 检查执行日期是否为交易日
            if not self.trade_calendar.is_trade_day(execution_date):
                self.logger.info(
                    f"日期 {execution_date} 不是交易日，跳过收盘统计任务执行"
                )
                return

            if target_date:
                self.logger.info(f"开始执行收盘统计任务，指定日期: {target_date}")
            else:
                self.logger.info("开始执行收盘统计任务")

            # 获取所有活跃股票
            active_stocks = self.mnjt_repo.get_active_stocks()

            self.logger.info(f"获取到 {len(active_stocks)} 只活跃股票")

            if not active_stocks:
                self.logger.info("没有需要更新的活跃股票")
                return

            # 获取股票代码列表
            stock_codes = [stock["code"] for stock in active_stocks]

            # 批量获取股票价格和成交量
            if target_date and target_date != date.today():
                # 如果指定了历史日期，使用历史数据接口
                stock_prices = self.api_service.get_historical_stocks_by_codes(
                    stock_codes, target_date
                )
            else:
                # 否则使用实时接口
                stock_prices = self.api_service.get_stocks_by_codes(stock_codes)

            success_count = 0
            end_count = 0

            for stock_record in active_stocks:
                stock_code = stock_record["code"]

                # 获取当前价格和成交量
                if stock_code not in stock_prices:
                    self.logger.warning(f"无法获取股票 {stock_code} 的价格信息，跳过")
                    continue

                stock_info = stock_prices[stock_code]
                # 优先使用API明确返回的当天收盘价(f18字段在实时接口中代表昨收，但在历史接口中可能代表当天收盘价，需根据API行为确定)
                # 为确保逻辑清晰，收盘统计统一使用current_price，因为它在收盘后代表的就是收盘价
                current_price = stock_info.current_price
                current_volume = stock_info.volume or 0  # 获取成交量

                if not current_price or current_price <= 0:
                    self.logger.warning(
                        f"股票 {stock_code} 当前价格异常: {current_price}，跳过"
                    )
                    continue

                # 直接使用API返回的涨跌幅，不再手动计算
                # 手动计算可能因价格精度问题导致与API返回的官方涨跌幅有微小差异
                change_percent = stock_info.change_percent or 0

                # 正确计算持仓天数：基于买入日期到今天的交易日数量
                buy_date = stock_record["buy_dtm"]
                if isinstance(buy_date, str):
                    buy_date = datetime.strptime(buy_date, "%Y-%m-%d").date()
                elif hasattr(buy_date, "date"):
                    buy_date = buy_date.date()

                # 使用目标日期或今天作为计算基准日期
                end_date = target_date if target_date else date.today()
                # 如果基准日期不是交易日，记录警告但继续处理
                if not self.trade_calendar.is_trade_day(end_date):
                    self.logger.debug(f"基准日期 {end_date} 不是交易日，将用于天数计算")

                # 计算从买入日期到目标日期的交易日数量
                trade_days_held = self.trade_calendar.get_trade_days_in_range(
                    buy_date, end_date
                )
                current_days = len(trade_days_held) if trade_days_held else 1

                # 判断是否结束监听
                is_end = "Y" if current_days >= self.hold_days else "N"
                if is_end == "Y":
                    end_count += 1

                # 更新数据库记录（包含成交量）
                try:
                    if stock_code == "603717":
                        self.logger.info(
                            f"【DEBUG 603717】准备更新数据库: code={stock_code}, price={current_price}, change%={change_percent}, days={current_days}, volume={current_volume}, is_end={is_end}"
                        )
                    self.mnjt_repo.update_stock_daily_with_volume(
                        stock_record["id"],
                        current_price,
                        change_percent,
                        current_days,
                        current_volume,  # 记录成交量到chengjiaoliang字段
                        is_end,
                    )
                    success_count += 1

                    status = "结束监听" if is_end == "Y" else "继续监听"
                    self.logger.info(
                        f"更新股票 {stock_code}，价格: {current_price:.2f}，涨幅: {change_percent:.2f}%，成交量: {current_volume}，天数: {current_days}，{status}"
                    )

                except Exception as e:
                    self.logger.error(f"更新股票 {stock_code} 记录失败: {e}")

            self.logger.info(
                f"收盘统计任务完成，成功更新: {success_count}，结束监听: {end_count}"
            )

        except Exception as e:
            self.logger.error(f"执行收盘统计任务失败: {e}")

    def get_trading_summary(self) -> Dict[str, Any]:
        """获取交易汇总信息"""
        try:
            # 获取所有记录的统计信息
            query = """
            SELECT 
                COUNT(*) as total_count,
                COUNT(CASE WHEN isend = 'Y' THEN 1 END) as completed_count,
                COUNT(CASE WHEN isend != 'Y' OR isend IS NULL THEN 1 END) as active_count,
                AVG(zhangfu) as avg_return,
                MAX(zhangfu) as max_return,
                MIN(zhangfu) as min_return
            FROM [GP].[dbo].[mnjt]
            """

            result = self.mnjt_repo.execute_query(query)

            if result:
                summary = result[0]
                return {
                    "total_stocks": summary.get("total_count", 0),
                    "completed_stocks": summary.get("completed_count", 0),
                    "active_stocks": summary.get("active_count", 0),
                    "avg_return": round(summary.get("avg_return", 0), 2),
                    "max_return": round(summary.get("max_return", 0), 2),
                    "min_return": round(summary.get("min_return", 0), 2),
                    "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                }
            else:
                return {
                    "total_stocks": 0,
                    "completed_stocks": 0,
                    "active_stocks": 0,
                    "avg_return": 0,
                    "max_return": 0,
                    "min_return": 0,
                    "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                }

        except Exception as e:
            self.logger.error(f"获取交易汇总失败: {e}")
            return {
                "total_stocks": 0,
                "completed_stocks": 0,
                "active_stocks": 0,
                "avg_return": 0,
                "max_return": 0,
                "min_return": 0,
                "update_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "error": str(e),
            }

    def manual_buy_task(self, target_date: date = None):
        """手动执行买入任务"""
        if target_date is None:
            target_date = date.today()

        self.logger.info(f"手动执行买入任务，目标日期: {target_date}")

        # 提醒用户交易日状态
        if not self.trade_calendar.is_trade_day(target_date):
            self.logger.warning(f"目标日期 {target_date} 不是交易日，任务将被跳过")

        # 检查是否已有买入记录
        if self.mnjt_repo.has_buy_records_for_date(target_date):
            self.logger.warning(f"{target_date} 已有买入记录，请确认是否重复执行")

        self.execute_buy_task(target_date)

    def manual_sell_task(self, target_date: date = None):
        """手动执行收盘统计任务"""
        execution_date = target_date if target_date else date.today()

        if target_date:
            self.logger.info(f"手动执行收盘统计任务，指定日期: {target_date}")
        else:
            self.logger.info("手动执行收盘统计任务")

        # 提醒用户交易日状态
        if not self.trade_calendar.is_trade_day(execution_date):
            self.logger.warning(f"执行日期 {execution_date} 不是交易日，任务将被跳过")

        self.execute_sell_task(target_date)
